/*
 * aes_cipher_stream.cxx
 *
 *  Created on: Apr 6, 2011
 *      Author: Erich Malzer
 */

#include "crypto/aes_cipher_stream.h"
#include "logger.h"


CAESCipherStream::CAESCipherStream(std::string *pPassword) {
	mAES = new OFB_Mode<AES>::Encryption();

	// Hash the password with SHA256
	SHA256 sha256Hash;
	byte hash[sha256Hash.DIGESTSIZE];
	sha256Hash.CalculateDigest(hash, (byte *)pPassword->data(), pPassword->length());


	printl(0, __FILE__, "SHA256 password hash: %s \n", (CAESCipherStream::hexEncode(hash, sizeof(hash))).data());

	// For now, we let the iv (128-bit) be the first half of the hashed password (should be random later on)
	byte iv[16];

	for (int i=0; i<16; i++) {
		iv[i] = hash[i];
	}

	// Initialize the AES object
	mAES->SetKeyWithIV(hash, sizeof(hash), iv);

	// Get the constant Cipher Stream data
	getNext(&mStaticCipherStream, 2048);
}

CAESCipherStream::~CAESCipherStream() {
	// TODO Auto-generated destructor stub
}


void CAESCipherStream::getNext(std::string *pStream, unsigned int pCount) {
	// Create a char array with <pCount> length and make it full of zeros (that's our "plain text")
	char plainChar[pCount];
	memset(plainChar, 0x00, pCount);
	string plain(plainChar, pCount);

	//cout << "Plaintext length: " << plain.length() << endl;
	//cout << CAESCipherStream::hexEncode((byte *)plain.data(), 128) << endl;

	// Here, the actual encryption is done
	pStream->clear();
	StringSource(plain, true,
		new StreamTransformationFilter(*mAES,
			new StringSink(*pStream)
		)
	);

	//cout << "Cipher: " << CAESCipherStream::hexEncode((byte *)cipher.data(), cipher.length()) << ", length: " << cipher.length() << endl;
}

/* gets every time the same cipher stream */
bool CAESCipherStream::getStaticKey(std::string *pStream, unsigned int pCount, unsigned int pOffset){
	if(pCount>mStaticCipherStream.size()){
		return false;
	}
	*pStream = std::string(mStaticCipherStream.substr(pOffset,pCount));
	return true;
}

void CAESCipherStream::reset(std::string *pPassword) {

}

std::string CAESCipherStream::hexEncode(byte *pData, int pSize) {
	string encoded;
	encoded.clear();
	StringSource(pData, pSize, true,
		new HexEncoder(
			new StringSink(encoded)
		) // HexEncoder
	); // StringSource

	return encoded;
}
